﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zeus.Comunicaciones.Componentes.AccesoDatos;
using Zeus.Comunicaciones.Componentes.Excepciones;
using Zeus.Comunicaciones.Utilidades.Cryptography;

namespace Zeus.Comunicaciones.Componentes
{
    public class Autenticacion : IAutenticacion
    {
        protected Md5 md5 = new Md5();
        protected ZeusServiciosEntities dataContext = new ZeusServiciosEntities();

        /// <summary>
        /// Obtiene la durabilidad en minutos del token a partir del parametros en el archivo de configuración
        /// </summary>
        protected double TokenDurabilidad
        {
            get
            {
                return double.Parse(ConfigurationManager.AppSettings["TokenDurability"]);
            }
        }

        public string Autenticar(string user, string pass)
        {
            pass = md5.Encrypt(pass);

            Usuarios usuario = dataContext.Usuarios.SingleOrDefault(t => t.Usuario == user && t.Contrasena == pass);

            if (usuario != default(Usuarios))
            {
                if (!usuario.Autorizado)
                {
                    throw new InactiveUserException();
                }

                usuario.UltimoAcceso = DateTime.Now;

                string token = Guid.NewGuid().ToString();

                Autorizaciones autorizacion = new Autorizaciones
                {
                    FechaCreacion = DateTime.Now,
                    FechaCaducidad = DateTime.Now.AddMinutes(TokenDurabilidad),
                    Usuario = user,
                    Guid = token
                };

                dataContext.Autorizaciones.Add(autorizacion);
                dataContext.SaveChanges();

                return token;
            }
            else
            {
                throw new WrongUserOrPasswordException();
            }
        }

        public bool ValidarToken(string token)
        {
            Autorizaciones autorizacion = dataContext.Autorizaciones.SingleOrDefault(t => t.Guid.Equals(token, StringComparison.InvariantCultureIgnoreCase));

            if (autorizacion == default(Autorizaciones))
            {
                throw new InvalidTokenException();
            }

            if (autorizacion.FechaCaducidad < DateTime.Now)
            {
                throw new InactiveUserException();
            }

            autorizacion.FechaCaducidad.AddMinutes(TokenDurabilidad);
            dataContext.SaveChanges();

            return true;
        }

        public bool ValidarPrivilegios(Privilegios privilegio, string token = null, string user = null)
        {
            //Si el usuario es null este se busca a partir del token
            if (user == null)
            {
                try
                {
                    if (ValidarToken(token))
                    {
                        Autorizaciones autorizacion = dataContext.Autorizaciones.SingleOrDefault(t => t.Guid == token);
                        user = autorizacion.Usuario;
                    }
                }
                catch
                {
                    return false;
                }
            }

            Usuarios usuario = dataContext.Usuarios.SingleOrDefault(t => t.Usuario == user);

            Privilegios privilegioContext = dataContext.Privilegios.SingleOrDefault(t => t.Metodo == privilegio.Metodo &&
                t.RutaPrefijo == privilegio.RutaPrefijo && t.Servicio == privilegio.Servicio);

            return usuario.Roles.Count(t => t.Privilegios.Contains(privilegioContext)) > 0;
        }
    }
}
